﻿using System;
using System.Dynamic;
using System.Collections.Specialized;
using System.Collections;

namespace Ruandao.MiniFace
{
    /// <summary>
    /// An implementation of a NameValueCollection which uses dynamics to allow property accessors
    /// </summary>
    /// <remarks>
    /// <para>
    /// This class inherits from <see cref="System.Dynamic.DynamicObject"/> and <see cref="System.Collections.Specialized.NameValueCollection"/> 
    /// (to give default ICollection  features well).
    /// It allows you to have a name values which you access the key store via standard dot-notation. This is exposed via extension methods for users to create.
    /// </para>
    /// <example>
    ///     var nameValues = Request.QueryString.AsDynamic();
    ///     //access data
    ///     var local = nameValues.id;
    ///     //create new key
    ///     nameValues.newValue = "I'm new!";
    /// </example>
    /// </remarks>
    /// <typeparam name="string">The type of the key.</typeparam>
    /// <typeparam name="string">The type of the value.</typeparam>
    public sealed class DynamicNameValueCollection : DynamicObject, ICollection, System.Collections.IEnumerable    
    {
        private NameValueCollection nameValues;

        /// <summary>
        /// Initializes a new instance of the <see cref="DynamicNameValueCollection&lt;string, string&gt;"/> class.
        /// </summary>
        public DynamicNameValueCollection()
            : this(new NameValueCollection())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DynamicNameValueCollection&lt;string, string&gt;"/> class from a given NameValueCollection
        /// </summary>
        /// <param name="nameValues">The NameValueCollection.</param>
        public DynamicNameValueCollection(NameValueCollection nameValues)
        {
            //set the internal instance.
            this.nameValues = nameValues;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            // 由于NameValueCollection不区分不包含键和包含但值为null这两种情况。
            // 不论键是否存在都会返回值，只不过该值可能为null。
            result = nameValues.Get(binder.Name);
            if (result == null) result = "";
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            nameValues.Set(binder.Name, value.ToString());
            return true;
        }

        public override bool TryDeleteMember(DeleteMemberBinder binder)
        {
            nameValues.Remove(binder.Name);
            return true;
        }

        #region ICollection

        public void CopyTo(Array array, int index)
        {
            nameValues.CopyTo(array, index);
        }

        public int Count
        {
            get { return nameValues.Count; }
        }

        public bool IsSynchronized
        {
            get { return ((ICollection)nameValues).IsSynchronized; }
        }

        public object SyncRoot
        {
            get { return ((ICollection)nameValues).SyncRoot; }
        }

        public IEnumerator GetEnumerator()
        {
            return nameValues.GetEnumerator();
        }

        #endregion
    }
}
